<?php
include_once 'db.inc';

class AbstractObject {

    /**
     *
     * @var array Datos correspondientes a los campos de la base de datos.
     */
    protected $data = array();

    /*
     * Variables que indican la accion realizada al hacer una consulta.
     */
    protected $__INSERT__ = 1;
    protected $__UPDATE__ = 2;
    protected $action = 0;

    /**
     *
     * @var string Mensaje el cual indica algun error. 
     */
    public $msg = null;

    /*
     * Constructores
     */

    /**
     * Crea e inicia el objeto con su respectiva informacion <br>
     * a partir de su numero de id.
     * 
     * @param int $id
     * @return objeto
     */
    public static function Id($id) {
        $ins = new static();
        $ins->id = $id;
        $ins->byId();
        return $ins;
    }

    /**
     * Crea e inicia el objeto con su respectiva informacion <br>
     * a partir de su numero encriptado de id.
     * 
     * @param string $id
     * @return objeto
     */
    public static function EId($id) {
        $ins = new static();
        $ins->id = $id;
        $ins->byEId();
        return $ins;
    }

    /*
     * Metodos Magicos. Son llamados al asignar u obtener informacion 
     * de la clase.
     */

    public function __set($name, $value) {
        $this->data[$name] = $value;
    }

    public function __get($name) {
        if (array_key_exists($name, $this->data)) {
            return utf8_encode($this->data[$name]);
        }
        return null;
    }

    public function __isset($name) {
        return isset($this->data[$name]);
    }

    public function __unset($name) {
        unset($this->data[$name]);
    }

    /**
     * Asigna los valores de los atributos de la clase.
     * 
     * @param array $data Matriz de datos.
     */
    public function setData($data) {
        $this->data = $data;
    }

    /**
     * Devuelve los valores de los atributos de la clase.
     * 
     * @return array $data Matriz de datos.
     */
    public function getData() {
        return $this->data;
    }

    /**
     * Encripta la id del objeto.
     * 
     * @return string Id encriptada.
     */
    public function encodeId() {
        if ($this->id !== null) {
            return urlencode(sprintf("%016d", $this->id));
        }
        return null;
    }

    /**
     * Desencripta la id del objeto.
     * 
     * @return string Id desencriptada.
     */
    public function decodeId() {
        return sprintf("%d", urldecode($this->id));
    }

    /**
     * Incia el objeto a partir de su numero de id encriptado.
     * 
     * @param string $id Id encriptada.
     */
    public function byEId() {
        $this->id = $this->decodeId();
        $this->byId();
    }

    /**
     * Incia el objeto a partir de su numero de id.
     * 
     * @param int $id Numero de Id
     */
    public function byId() {
        $db = new MariaDB();
        if (!$db->error()) {
            if ($db->query("SELECT * FROM $this->tabla WHERE id='$this->id'")) {
                if ($db->fetch_assoc()) {
                    $this->setData($db->row());
                }
                $db->free();
            } else {
                $this->msg = $db->error();
            }
            $db->close();
        } else {
            $this->msg = $db->error;
            return false;
        }
    }

    /**
     * Prepara una consulta para insertar informacion en la base de datos.
     * 
     * @return string Consulta SQL a partir de la informacion alamacenada.
     */
    protected function prepare_insert() {
        $this->action = $this->__INSERT__;
        $this->id = "null";
        foreach ($this->data as $key => $value) {
            isset($vals) ? $vals .= ',' : $vals = '';
            if ($key === "id")
                $vals .= $value;
            else
                $vals .= '\'' . urldecode($value) . '\'';
        }
        $cols = implode(',', array_keys($this->data));
        return "INSERT INTO $this->tabla ($cols) VALUES ($vals)";
    }

    /**
     * Prepara una consulta para actualizar informacion en la base de datos.
     * 
     * @return string Consulta SQL a partir de la informacion alamacenada.
     */
    protected function prepare_update() {
        $this->action = $this->__UPDATE__;
        $this->id = $this->decodeId();
        foreach ($this->data as $key => $value) {
            isset($val) ? $val .= ',' : $val = '';
            $val .= $key . '=\'' . urldecode($value) . '\'';
        }
        return "UPDATE $this->tabla SET $val WHERE id=" . $this->id;
    }

    /**
     * Realiza una consulta a la base de datos.
     * 
     * @param type $query Consulta SQL.
     * @return boolean <b>true</b> en caso de exito.
     * <b>false</b> en caso de error.
     */
    protected function query($query) {
        $db = new MariaDB();
        if (!$db->error()) {
            if (!$db->query($query)) {
                $this->msg = $db->error();
                return false;
            }
        } else {
            $this->msg = $db->error();
            return false;
        }
        if ($this->action === $this->__INSERT__) {
            $this->id = $db->insert_id;
        }
        $db->close();
        return true;
    }

    /**
     * Guarda la informacion del objeto en la base de datos.
     * 
     * @return boolean <b>true</b> en caso de exito.
     * <b>false</b> en caso de error.
     */
    public function save() {
        if ($this->id === "") {
            $query = $this->prepare_insert();
        } else {
            $query = $this->prepare_update();
        }
        return $this->query($query);
    }

    /**
     * Elimina el objeto de la base de datos.
     * 
     * @return boolean <b>true</b> en caso de exito.
     * <b>false</b> en caso de error.
     */
    public function delete() {
        $query = "DELETE FROM $this->tabla WHERE id='$this->id'";
        return $this->query($query);
    }

    /**
     * Elimina el objeto de la base de datos. <br>
     * A partir de la id encriptada.
     * 
     * @param string $id Id encriptada.
     * @return boolean <b>true</b> en caso de exito.
     * <b>false</b> en caso de error.
     */
    public function deleteE($id) {
        $this->id = $id;
        $this->id = $this->decodeId();
        return $this->delete();
    }

    /**
     * Devuelve los objetos de la base de datos. 
     * 
     * @param string $field [optional]
     * @param string $value [optional]
     * @param int $count [optional]
     * @param int $init [optional]
     * @return array Objetos contenidos en la base de datos.
     * <b>false</b> en caso de error.
     */
    public function getAllBy($field = false, $value = null, $count = false, $init = 0) {
        $return = array();
        $where = "";
        $limit = "";
        if ($field) {
            $where = " WHERE $field='$value'";
        }
        if ($count) {
            $limit = " LIMIT $init," . ($init + $count);
        }
        $db = new MariaDB();
        if (!$db->error()) {
            if ($db->query(sprintf("SELECT * FROM %s %s %s", $this->tabla, $where, $limit))) {
                while ($db->fetch_assoc()) {
                    $obj = new static();
                    $obj->setData($db->row());
                    $return[] = $obj;
                }
                $db->free();
            } else {
                $this->msg = $db->error();
            }
            $db->close();
        } else {
            $this->msg = $db->error();
            return false;
        }
        return (empty($return) ? false : $return);
    }

    /**
     * Crea un conjunto de radio buttons.
     * 
     * @param string $title
     * @param string $name
     * @param array $values
     * @param string $checked
     */
    public function radioForm($title, $name, $values, $checked) {
        ?>
        <fieldset class="form">
            <legend class="form"><?php echo $title; ?></legend>
            <span>
                <?php foreach ($values as $key => $value) {
                    ?>
                    <input type="radio" name="<?php echo $name; ?>" value="<?php echo $key; ?>" <?php echo ($checked === $key ? "checked='checked'" : ""); ?> ><label><?php echo $value; ?></label>
                <?php } ?>
            </span>
        </fieldset>
        <?php
    }

    /**
     * 
     * @param type $name
     * @param type $selected Selected Id
     * @param type $func [optional]
     * @return string
     */
    function getSelect($name, $selected, $func = false) {
        $return = "<span><select id=\"" . $name . "_id\" name=\"" . $name . "_id\" " . (!$func ? "" : "onchange=\"$func();\"") . ">";
        $objArray = $this->getAllBy();
        if($objArray)
        foreach ($objArray as $obj) {
            $return .= sprintf("<option value=\"%s\" %s >%s</option>", $obj->encodeId(), ($selected === $obj->id ? "selected=\"seleceted\"" : ""), $obj->$name);
        }
        $return .= "</select></span>";
        return $return;
    }

}
?>
